<?php
/**
 * @copyright Copyright (c) 2019
 */

namespace lujie\proxy;


use Workerman\Connection\AsyncTcpConnection;
use Workerman\Connection\TcpConnection;
use Workerman\Worker;

class HttpProxyServer extends Worker
{
    public $name = 'HttpProxyServer';

    public $authEnabled = true;
    public $username = 'HttpProxyUsername';
    public $password = 'HttpProxyPassword';

    /**
     * @inheritdoc
     */
    public function run()
    {
        $this->onMessage = [$this, 'onMessage'];
        parent::run();
    }

    /**
     * @param TcpConnection $connection
     * @param string $buffer
     */
    public function onMessage(TcpConnection $connection, string $buffer): void
    {
        $headers = HttpHelper::parseHeader($buffer);
        if ($headers === null) {
            if (strlen($buffer) >= 16384) {
                $connection->close("HTTP/1.1 413 Request Entity Too Large\r\n\r\n");
                return;
            }
        }
        if ($this->authEnabled) {
            if (empty($headers['Proxy-Authorization'])) {
                $connection->send("HTTP/1.1 407 Proxy Authorization Required\r\nProxy-Authenticate: Basic realm=\"Access to the proxy\"\r\n\r\n");
                return;
            }
            $authorization = 'Basic ' . base64_encode($this->username . ':' . $this->password);
            if ($headers['Proxy-Authorization'] !== $authorization) {
                $connection->close("HTTP/1.1 401 Proxy Authorization Failed\r\n\r\n");
                return;
            }
        }
        $urlData = parse_url($headers['address']);
        $addr = $urlData['host'] . ':' . ($urlData['port'] ?? 80);
        $remoteConnection = new AsyncTcpConnection("tcp://$addr");
        if ($headers['method'] === 'CONNECT') {
            $connection->send("HTTP/1.1 200 Connection Established\r\n\r\n");
        } else {
            $remoteConnection->send($buffer);
        }
        $remoteConnection ->pipe($connection);
        $connection->pipe($remoteConnection);
        $remoteConnection->connect();
    }
}